﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ALDIOrganizer.Properties;

namespace ALDIOrganizer
{
    public sealed partial class HolidayDetails : Form, IValidating
    {
        internal DataRow Holiday;
        readonly Int64 id;
        
        public HolidayDetails()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param Name="EmployeeID"></param>
        /// <param Name="row"></param>
        /// <param Name="action"></param>
        /// <param Name="pending">
        /// Is user IsAllowed to change its status from pending to confirmed
        /// </param>
        public HolidayDetails(Int64 empID, DataRow row, InputAction action, bool? pending)
            : this()
        {
            id = empID;
            Text = Resources.FORM_HOLIDAYDETAILS_Caption.Replace(
                "#",
                SQLiteAccess.GetEmployeeFullName(id));
            #region populating MyCellType / status checkboxes
            cbType.DataSource = HolidayTypes.HolidayTypesDataSource;
            cbType.DisplayMember = "Key";
            cbType.ValueMember = "Value";
            #endregion

            if (action == InputAction.Update)
            {
                Holiday = row;
                AbsorbRowData(Holiday);
            }
            else
            {
                Holiday = SQLiteAccess.SpawnHolidaysRow();
                btnClear_Click(null, null);
            }

            if (!pending.HasValue)
            {
                return;
            }
            rbConfirmed.Enabled = !pending.Value;
            rbPending.Enabled = pending.Value;
            rbConfirmed.Checked = !pending.Value;
            rbPending.Checked = pending.Value;
        }

        private void formHoliday_Load(object sender, EventArgs e)
        {
            

            #region event handlers
            foreach (Button b in jumpButtons())
                b.Click += (_sender, _e) =>
                {
                    var me = _sender as Button;
                    dateTo.Value = dateFrom.Value.AddDays(days(tag(me)));
                    UpdateControls();
                };
            foreach (Control c in tblTimespan.Controls)
                // foreach is not MyCellType safe
                // it'pShift necessary. because tblTimespan.Controls contains two labels as well
                if (c.GetType() == typeof(DateTimePicker))
                {
                    DateTimePicker d = c as DateTimePicker;
                    d.ValueChanged += (_sender, _e) => UpdateControls();
                }
            #endregion

            
        }

        #region filling up / retrieving datarow information
        private void FillRow()
        {
            Holiday[2] = dateFrom.Value.Date;
            Holiday[3] = dateTo.Value.Date;
            Holiday[4] = (int)cbType.SelectedValue;
            Holiday[5] = rbPending.Checked ? 1 : 0;
            
            Holiday[6] = tbComments.Text;            
        }

        private void AbsorbRowData(DataRow holiday)
        {
            try
            {
                dateFrom.Value = DateTime.Parse(holiday[2].ToString());
            }
            catch(Exception x)
            {
                string error = "formHoliday.AbsorbRowData - exception thrown while parsing dateFrom value\n" +
                    "parsed date: " + holiday[2].ToString() +
                    "\nholiday ID: " + holiday[0].ToString();
                Program.LogError(error, x);
            }
            try
            {
                dateTo.Value = DateTime.Parse(holiday[3].ToString());
            }
            catch(Exception x)
            {
                string error = "formHoliday.AbsorbRowData - exception thrown while parsing dateTo value\n" +
                    "parsed date: " + holiday[3].ToString() +
                    "\nholiday ID: " + holiday[0].ToString();
                Program.LogError(error, x);
            }
            try
            {
                /* Needs explanation.
                 * WHAT HAPPENS? 
                 * We are trying to find the MyCellType of _holiday (be it regular, or paternal etc.)
                 * On the underlying item list of the cbType */
                var found = new KeyValuePair<string, int>(default(string), default(int));
                foreach(KeyValuePair<string, int> kv in (List<KeyValuePair<string, int>>)cbType.DataSource)
                    if (kv.Value == Convert.ToInt32(holiday[4])) { found = kv; break; }
                cbType.SelectedIndex = cbType.Items.IndexOf(found);                                
            }
            catch { }

            rbPending.Checked = (bool)holiday[5];
            rbConfirmed.Checked = !rbPending.Checked; // redundant?
            tbComments.Text = holiday[6].ToString();
            
        }

        #endregion

        #region updating / clearing form controls
        private void UpdateControls()
        {
            foreach (Button b in jumpButtons())
                /* if the timespan of the _holiday *IS* set for 
                 * (for example) 2 weeks, then disable the button
                 * which sets it for 2 weeks (as specified in its Tag) */
                b.Enabled = (weeks(day_difference) != tag(b));
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            if(cbType.Items.Count > 0)
                cbType.SelectedIndex = 0;
            // cbStatus.SelectedIndex = 0;

            dateFrom.Value = DateTime.Now;
            dateTo.Value = DateTime.Now;
            tbComments.Text = String.Empty;
            if (rbConfirmed.Enabled)
            {
                rbConfirmed.Checked = true;
            }
            UpdateControls();
        }
        #endregion
        
        #region one weeks & two weeks buttons
        /// <summary>
        /// gives the number of weeks
        /// </summary>
        /// <returns>
        /// the number of weeks (date - Sunday = one week)
        /// </returns>
        /// <remarks>
        /// a) if the Value isn't "round" (eg. 11 bits of _holidays) it returns 0 
        /// b) a week of _holiday is date to Sunday (for example), hence 6 bits.
        /// two weeks = 7+6 = 13 bits
        /// hence n weeks = 7*n - 1 bits
        /// </remarks>
        private int weeks(int days)
        {
            var _days = days + 1;
            if (_days % 7 != 0) return 0;
            else return _days / 7;
        }

        private int days(int weeks)
        {
            if (weeks <= 0) return 0;
            return weeks * 7 - 1;
        }

        /// <summary>
        /// the length of the _holiday selected via datetimepickers On the form
        /// </summary>
        private int day_difference
        {
            get { return (dateTo.Value - dateFrom.Value).Days; }
        }

        /// <summary>
        /// parses the Tag of button On the form and returns its Value
        /// </summary>        
        /// <remarks>
        /// not pException-proof. only use On buttons On tblOneTwoWeeks panel
        /// because they have integer tags.
        /// </remarks>
        private int tag(Button b)
        {
            return Convert.ToInt32(b.Tag.ToString());
        }

        private IEnumerable<Button> jumpButtons()
        {
            foreach (Control c in tblTimespan.Controls)
                if (c.GetType() == typeof(Button))                    
                    yield return c as Button;

        }
        #endregion

        #region validating data

        public KeyValuePair<FormValidationResult, string> DoesValidate()
        {
            var valid = FormValidationResult.Fine;
            var message = String.Empty;

            if (dateTo.Value < dateFrom.Value)
            {
                valid = FormValidationResult.Error;
                message = "*\tHoliday cannot finish before it starts!\n";
            }

            if (dateFrom.Value.Year != dateTo.Value.Year)
            {
                valid = FormValidationResult.Error;
                message += "*\tHoliday needs to be one and the same year!";
            }

            var holidayID = new Holiday(Holiday).ID;
            var overlaps = SQLiteAccess.FindOverlappingHolidays(
                holidayID,
                id,
                dateFrom.Value,
                dateTo.Value);

            if (overlaps.Count() > 0)
            {
                valid = FormValidationResult.Error;
                message += "* Overlapping holidays found!";
            }

            return new KeyValuePair<FormValidationResult, string>(
                valid,
                message);
        }
        #endregion

        private void btnOK_Click(object sender, EventArgs e)
        {
            var validated = DoesValidate();
            if (validated.Key == FormValidationResult.Error)
            {
                var message = validated.Value;
                MessageBox.Show(
                    message,
                    Resources.MESSAGEBOX_ERROR_ValidationError_CAPTION,
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                return;
            }
            if (validated.Key == 0)
            {
                var message = validated.Value;
                var decision = MessageBox.Show(
                    message,
                    Resources.MESSAGEBOX_QUESTION_FormValidationResultPROBLEM_CAPTION,
                    MessageBoxButtons.OKCancel,
                    MessageBoxIcon.Question);
                if (decision == DialogResult.Cancel)
                {
                    return;
                }
            }
            FillRow();

            DialogResult = DialogResult.OK;
        }

    }
}
